package ru.spb.osll.myfit.client.view;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.logical.shared.BeforeSelectionEvent;
import com.google.gwt.event.logical.shared.BeforeSelectionHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import ru.spb.osll.myfit.client.Mode;
import ru.spb.osll.myfit.client.dialog.ErrorDialog;
import ru.spb.osll.myfit.client.event.PageButtonEvent;
import ru.spb.osll.myfit.client.manager.PageExecutingManager;
import ru.spb.osll.myfit.client.service.ChartsService;
import ru.spb.osll.myfit.client.service.ChartsServiceAsync;
import ru.spb.osll.myfit.client.service.FitService;
import ru.spb.osll.myfit.client.service.FitServiceAsync;
import ru.spb.osll.myfit.client.widget.*;
import ru.spb.osll.myfit.common.ExecutingResult;
import ru.spb.osll.myfit.common.Page;
import ru.spb.osll.myfit.common.PageExecutingResult;
import ru.spb.osll.myfit.common.TestResultMetadataConstants;
import ru.spb.osll.myfit.common.chart.Chart;
import ru.spb.osll.myfit.common.chart.ChartInfo;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: Artem Bukhonov
 * Email: nerzhulart@gmail.com
 * Date: 10.12.11
 * Time: 15:42
 */
public class TestResultView extends AbstractTestView {

  // Services
  private final ChartsServiceAsync m_chartsService = GWT.create(ChartsService.class);
  private final FitServiceAsync m_fitService = GWT.create(FitService.class);

  // Controls
  private TabLayoutPanel m_tabLayoutPanel = new TabLayoutPanel(1.5, Style.Unit.EM);
  private VerticalPanel m_chartsPanel = new VerticalPanel();
  private LogPanel m_logPanel = new LogPanel();
  private VerticalPanel m_metadataPanel = new VerticalPanel();
  private Grid m_metadataTable;
  private ErrorDialog m_errorDialog = new ErrorDialog();
  private ProgressBar m_progressBar = new ProgressBar();
  private ProgressLabel m_progressLabel = new ProgressLabel();
  private PageButton m_expandButton, m_collapseButton, m_saveMetadataButton;
  private PageWidget m_pageWidget = new PageWidget(new GWTWidgetFactory());
  private Label m_titleLabel = new Label();

  private PageExecutingManager m_pageExecutingManager = new PageExecutingManager();
  private String m_pageId;
  private String m_pagePath;
  private PageExecutingResult m_pageExecutingResult;

  private PageButtonEventListener m_buttonEventListener;
  
  private int previousTab = 0;


  public TestResultView(PageButtonEventListener pageButtonEventListener) {
    setProgressVisible(true);
    m_pageWidget.setOpen(true);
    ScrollPanel scrollTablesPanel = new ScrollPanel();
    scrollTablesPanel.setWidget(m_pageWidget);
    m_tabLayoutPanel.add(scrollTablesPanel, "Tables");
    ScrollPanel scrollChartsPanel = new ScrollPanel(m_chartsPanel);
    m_tabLayoutPanel.add(scrollChartsPanel, "Charts");
    m_tabLayoutPanel.add(m_logPanel, "Logs");
    m_tabLayoutPanel.add(m_metadataPanel, "Metadata");

    m_buttonEventListener = createButtonEventListener(pageButtonEventListener);

    m_tabLayoutPanel.addBeforeSelectionHandler(new BeforeSelectionHandler<Integer>() {
      @Override
      public void onBeforeSelection(BeforeSelectionEvent<Integer> event) {
        if ((event.getItem() == 0 || event.getItem() == 1) && previousTab == 2) {
          m_logPanel.setScrollPosition(m_logPanel.getElement().getScrollTop());
          previousTab = event.getItem();
        }
      }
    });

    m_tabLayoutPanel.addSelectionHandler(new SelectionHandler<Integer>() {
      @Override
      public void onSelection(SelectionEvent<Integer> event) {
        if (event.getSelectedItem() == 2) {
          previousTab = event.getSelectedItem();
          m_logPanel.scroll();
        }

        m_saveMetadataButton.setVisible(event.getSelectedItem() == 3);
      }
    });

    m_tabLayoutPanel.setStyleName("scrollableTabsContainer");
    m_titleLabel.setStyleName("testNameLabelStyle");
  }

  @Override
  protected Widget createContentPanel() {
    return m_tabLayoutPanel;
  }

  private void beginChartReceiving() {
    m_chartsService.getCharts(m_pageId,
            new AsyncCallback<List<Chart>>() {

              @Override
              public void onFailure(Throwable caught) {
                m_errorDialog.setMessage(caught);
                m_errorDialog.center();
              }

              @Override
              public void onSuccess(List<Chart> result) {
                m_chartsPanel.clear();
                for (Chart chart : result) {
                  //Image image = new Image(chart.getBase64Data());
                  //image.setStyleName("chartPicture");
                  final ChartWidget chartWidget = new ChartWidget();
                  chartWidget.addListener(new ChartWidget.ChartInfoChangedListener() {
                    @Override
                    public void changed(ChartInfo newInfo) {
                      m_chartsService.rebuildChart(m_pageId, newInfo, new AsyncCallback<Chart>() {
                        @Override
                        public void onFailure(Throwable throwable) {
                          m_errorDialog.center();
                        }

                        @Override
                        public void onSuccess(Chart chart) {
                          chartWidget.setChart(chart);
                        }
                      });
                    }
                  });
                  chartWidget.setChart(chart);
                  m_chartsPanel.add(chartWidget);
                }
              }
            });
  }

  private void beginLogReceiving() {
    m_logPanel.startGettingLogs(m_pagePath, m_pageId);
  }

  private PageButtonEventListener createButtonEventListener(final PageButtonEventListener pageButtonEventListener) {
    return new PageButtonEventListener() {

      @Override
      public void actionPerformed(PageButtonEvent event) {
        switch (event.getType()) {
          case COLLAPSE_ALL:
            m_pageWidget.setOpen(false);
            break;
          case EXPAND_ALL:
            m_pageWidget.setOpen(true);
            break;
          case BACK:
            Window.Location.assign(m_pagePath);
            break;
          default:
            pageButtonEventListener.actionPerformed(event);
            break;
        }
      }
    };
  }

  private void updateProgress() {
    m_progressBar.updateView(m_pageExecutingResult.getPercentage());
    m_progressLabel.updateView(m_pageExecutingResult.getStatusString());
    if (!m_pageExecutingResult.getState().equals(
            ExecutingResult.ExecutingState.FINISH)) {
      m_pageExecutingManager.addListener(m_pageId, m_progressBar);
      m_pageExecutingManager.addListener(m_pageId, m_progressLabel);
    }
  }

  public void displayResult(PageExecutingResult pageExecutingResult) {
    m_pageExecutingResult = pageExecutingResult;
    m_pageId = m_pageExecutingResult.getId();
    m_pagePath = m_pageExecutingResult.getName();
    m_expandButton.setVisible(true);
    m_collapseButton.setVisible(true);
    m_saveMetadataButton.setVisible(false);

    m_pageExecutingManager = new PageExecutingManager();
    m_pageWidget.clear();
    m_pageWidget.setMode(Mode.VIEW);
    m_pageWidget.setPagePath(m_pagePath);

    m_chartsPanel.clear();
    m_logPanel.clearLog();
    m_metadataPanel.clear();

    AsyncCallback<Page> displayPage = new AsyncCallback<Page>() {
              @Override
              public void onFailure(Throwable caught) {
                m_errorDialog.setMessage(caught);
                m_errorDialog.center();
              }

              @Override
              public void onSuccess(Page page) {
                loadTestsPage(page);
              }
    };

    if (pageExecutingResult.belongsToSuite()) {
      m_fitService.loadPageFromSuiteResultsDirectory(m_pagePath, pageExecutingResult.getSuiteResultId(), displayPage);
    } else {
      m_fitService.loadPageFromTestResultsDirectory(m_pagePath, m_pageId, displayPage);
    }
  }

  private void loadMetadata() {
    Map<String, String> metadata = m_pageExecutingResult.getMetadata();

    m_metadataTable = new Grid(metadata.size(), 2);

    int i = 0;
    for (Map.Entry<String, String> entry : metadata.entrySet()) {
      m_metadataTable.setText(i, 0, entry.getKey());

      if (entry.getKey().equals(TestResultMetadataConstants.TEST_RUN_COMMENT)) {
        TextArea textArea = new TextArea();
        textArea.setText(entry.getValue());

        m_metadataTable.setWidget(i, 1, textArea);
      } else {
        TextBox textBox = new TextBox();
        textBox.setText(entry.getValue());
        m_metadataTable.setWidget(i, 1, textBox);
      }

      i++;
    }
    m_metadataPanel.add(m_metadataTable);
  }

  public Map<String, String> getMetadata() {
    Map<String, String> metadata = new HashMap<String, String>();
    String key, value;
    String pattern = "[-A-Za-z0-9_:,.\\s]*";

    for (int i = 0; i < m_metadataTable.getRowCount(); i++) {
      key = m_metadataTable.getText(i, 0);
      if (key.equals(TestResultMetadataConstants.TEST_RUN_COMMENT)) {
        value = ((TextArea) m_metadataTable.getWidget(i, 1)).getText();
      } else {
        value = ((TextBox) m_metadataTable.getWidget(i, 1)).getText();
      }

      if (!value.matches(pattern)) {
        ErrorDialog dialog = new ErrorDialog();
        dialog.setMessage("Metadata contains invalid characters");
        dialog.center();
        return null;
      }else{
        metadata.put(key, value);
      }
    }
    return metadata;
  }

  private void loadTestsPage(Page page) {
    loadTestsResult(page);
    updateProgress();
    beginLogReceiving();
    loadMetadata();
  }

  private void loadTestsResult(Page page) {

    m_titleLabel.setText(m_pageExecutingResult.getName());

    m_pageWidget.setPage(page);
    m_pageExecutingManager.addListener(m_pageId, new PageExecutingListenerImpl(
            m_pageWidget));
    m_pageExecutingManager.addListener(m_pageId, new ExecutingListener() {
      @Override
      public void processExecutingResult(ExecutingResult result) {
      }

      @Override
      public void finish() {
        m_logPanel.stopGettingLogs();
        beginChartReceiving();
      }
    });
    m_pageExecutingManager.addResultToListen(m_pageExecutingResult);
  }

  @Override
  protected Widget createEditPanel() {
    VerticalPanel editPanel = (VerticalPanel) super.createEditPanel();
    editPanel.add(m_titleLabel);
    editPanel.add(createButtonPanel());
    return editPanel;
  }

  private Widget createButtonPanel() {
    Panel buttonPanel = new HorizontalPanel();
    buttonPanel.setWidth("100%");

    HorizontalPanel hPanel = new HorizontalPanel();
    hPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
    hPanel.setSpacing(5);
    hPanel.add(new PageButton("Back to Test page", "backToTestButtonStyle",
            PageButtonEvent.PageButtonEventType.BACK, m_buttonEventListener));
    HorizontalPanel separator = new HorizontalPanel();
    separator.setWidth("20");
    hPanel.add(separator);
    m_expandButton = new PageButton("Expand all", "expandAllIncludesButtonStyle",
            PageButtonEvent.PageButtonEventType.EXPAND_ALL, m_buttonEventListener);
    m_expandButton.setVisible(false);
    m_collapseButton = new PageButton("Collapse all", "collapseAllIncludesButtonStyle",
            PageButtonEvent.PageButtonEventType.COLLAPSE_ALL, m_buttonEventListener);
    m_collapseButton.setVisible(false);
    hPanel.add(m_expandButton);
    hPanel.add(m_collapseButton);
    m_saveMetadataButton = new PageButton("Save metadata", "sendButtonStyle", PageButtonEvent.PageButtonEventType.SAVE_METADATA, m_buttonEventListener);
    m_saveMetadataButton.setVisible(false);
    hPanel.add(m_saveMetadataButton);
    buttonPanel.add(hPanel);
    buttonPanel.add(createProgressPanel());
    return buttonPanel;
  }

  private Widget createProgressPanel() {
    HorizontalPanel panel = new HorizontalPanel();
    panel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
    panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
    panel.setSpacing(5);
    panel.setWidth("100%");
    panel.add(m_progressLabel);
    panel.add(m_progressBar);
    panel.setCellWidth(m_progressBar, "250px");
    return panel;
  }

  private void setProgressVisible(boolean isVisible) {
    m_progressBar.setVisible(isVisible);
    m_progressLabel.setVisible(isVisible);
  }
}
